Skip to content

Fix segfault on Windows when stdout is not a real console handle#125

Open
davesnx wants to merge 1 commit intoocaml-community:masterfrom
davesnx:fix-windows-console-segfault
Open

Fix segfault on Windows when stdout is not a real console handle#125
davesnx wants to merge 1 commit intoocaml-community:masterfrom
davesnx:fix-windows-console-segfault

Conversation

@davesnx
Copy link

@davesnx davesnx commented Mar 4, 2026

Summary

Fixes #124utop (and anything built on it, like Reason's rtop) segfaults on Windows in certain environments (e.g. GitHub Actions runners).

Problem

On some Windows environments, _isatty() returns true for handles that are not real console screen buffers. This likely happens due to ConPTY (Windows Pseudo Console). When lambda-term calls GetConsoleScreenBufferInfo on such a handle, it causes an access violation (segfault) instead of returning an error.

The crash path is:

  1. LTerm.createLwt_unix.isatty returns true for stdout
  2. Since outgoing_is_a_tty = true, get_size_from_fd is called
  3. The C stub lt_term_get_size_from_fd calls GetConsoleScreenBufferInfo(Handle_val(fd), &info) with no handle validation
  4. Access violation / segfault

Fix

  1. C stub level (lTerm_term_stubs.c): Validate handles with GetConsoleMode before calling GetConsoleScreenBufferInfo / SetConsoleWindowInfo. Invalid handles now raise a Unix_error instead of crashing.

  2. OCaml level (lTerm.ml): Wrap the get_size_from_fd call in LTerm.create with a try/catch. If getting the terminal size fails, fall back to treating the terminal as non-tty instead of crashing.

Testing

Tested by reproducing the issue on a GitHub Actions windows-latest runner with:

  • OCaml 4.14.3
  • lambda-term 3.3.3
  • utop 2.16.0

Before fix: echo "1 + 1;;" | utop 2>&1 → Segmentation fault
After fix: should raise a catchable OCaml exception and fall back to non-tty mode

On some Windows environments (e.g. GitHub Actions runners), _isatty()
returns true for handles that are not real console screen buffers
(likely due to ConPTY). Passing these handles to
GetConsoleScreenBufferInfo causes an access violation (segfault).

This adds two layers of defense:

1. C stub level: validate handles with GetConsoleMode before calling
   GetConsoleScreenBufferInfo/SetConsoleWindowInfo. Invalid handles now
   raise a Unix_error instead of crashing.

2. OCaml level: wrap the get_size_from_fd call in LTerm.create with a
   try/catch. If getting the terminal size fails, fall back to treating
   the terminal as non-tty instead of crashing.

Fixes ocaml-community#124
davesnx added a commit to reasonml/reason that referenced this pull request Mar 4, 2026
- Disable rtopIntegration test on Windows due to lambda-term segfault
  when stdout is not a real console handle (ConPTY issue on GH Actions).
  See: ocaml-community/lambda-term#125

- Add setup-mingw step in esy-ci for Windows to provide x86_64-w64-mingw32-gcc
  needed to compile lambda-term C stubs.

- Bump esy cache keys to v0.0.2 to avoid stale caches.
davesnx added a commit to reasonml/reason that referenced this pull request Mar 4, 2026
Pin lambda-term to davesnx/lambda-term#fix-windows-console-segfault
in opam-ci on Windows to test the ConPTY segfault fix end-to-end.

Re-enable rtopIntegration test on Windows for OCaml >= 5.0 (opam-ci
with 5.4.0 will exercise the fix). esy-ci uses 4.14 so the test is
naturally skipped there.

See: ocaml-community/lambda-term#125
davesnx added a commit to reasonml/reason that referenced this pull request Mar 5, 2026
* test(rtop): capture stderr in integration test for Windows

* ci: setup tmate

* test(rtop): avoid running rtop in windows 4.14.*

* ci: enable 5.4.0 in windows

* ci: remove action-tmate

* ci: revert all changes, keep building

* ci: add -preasonrtop in esy-ci

* ci: update cache keys

* ci: fix Windows CI failures

- Disable rtopIntegration test on Windows due to lambda-term segfault
  when stdout is not a real console handle (ConPTY issue on GH Actions).
  See: ocaml-community/lambda-term#125

- Add setup-mingw step in esy-ci for Windows to provide x86_64-w64-mingw32-gcc
  needed to compile lambda-term C stubs.

- Bump esy cache keys to v0.0.2 to avoid stale caches.

* ci: replace setup-mingw action with direct choco install

The egor-tensin/setup-mingw@v2 action fails on MinGW 15.2.0 because
its cleanup script tries to remove libpthread.dll.a which no longer
exists in UCRT-based builds. Use choco directly and add the bin
directory to PATH manually.

* ci: esy-ci doesn't run rtop tests on windows
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Segfault on Windows when stdout is not a real console handle

1 participant